package com.fanx.content.service.impl;

import com.alibaba.fastjson.JSON;
import com.fanx.base.execption.CommonError;
import com.fanx.base.execption.FanXPlusException;
import com.fanx.content.config.MultipartSupportConfig;
import com.fanx.content.feignclient.MediaServiceClient;
import com.fanx.content.mapper.CourseBaseMapper;
import com.fanx.content.mapper.CourseMarketMapper;
import com.fanx.content.mapper.CoursePublishMapper;
import com.fanx.content.mapper.CoursePublishPreMapper;
import com.fanx.content.model.dto.CourseBaseInfoDto;
import com.fanx.content.model.dto.CoursePreviewDto;
import com.fanx.content.model.dto.TeachplanDto;
import com.fanx.content.model.po.CourseBase;
import com.fanx.content.model.po.CourseMarket;
import com.fanx.content.model.po.CoursePublish;
import com.fanx.content.model.po.CoursePublishPre;
import com.fanx.content.service.CourseBaseInfoService;
import com.fanx.content.service.CoursePublishMService;
import com.fanx.content.service.TeachplanService;
import com.fanx.messagesdk.mapper.MqMessageMapper;
import com.fanx.messagesdk.model.po.MqMessage;
import com.fanx.messagesdk.service.MqMessageService;
import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 课程发布相关接口实现
 */
@Slf4j
@Service
public class CoursePublishServiceImpl implements CoursePublishMService {

    @Autowired
    CourseBaseInfoService courseBaseInfoService;

    @Autowired
    TeachplanService teachplanService;

    @Autowired
    MqMessageService mqMessageService;

    @Autowired
    CourseBaseMapper courseBaseMapper;

    @Autowired
    CourseMarketMapper courseMarketMapper;

    @Autowired
    CoursePublishPreMapper coursePublishPreMapper;

    @Autowired
    CoursePublishMapper coursePublishMapper;

    @Autowired
    MqMessageMapper mqMessageMapper;

    @Autowired
    MediaServiceClient mediaServiceClient;

    @Resource
    RedisTemplate redisTemplate;




    @Override
    public CoursePreviewDto getCoursePreviewInfo(Long courseId) {
        CoursePreviewDto coursePreviewDto = new CoursePreviewDto();
        //课程基本信息，营销信息
        CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(courseId);
        coursePreviewDto.setCourseBase(courseBaseInfo);
        //课程计划信息
        List<TeachplanDto> teachplanTree = teachplanService.findTeachplanTree(courseId);
        coursePreviewDto.setTeachplans(teachplanTree);
        return coursePreviewDto;
    }

    @Override
    @Transactional
    public void commitAudit(Long companyId, Long courseId) {

        CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(courseId);
        if (courseBaseInfo == null) {
            FanXPlusException.cast("课程找不到");
        }
        //审核状态为已提交则不允许提交
        String status = courseBaseInfo.getStatus();
        if (status.equals("202003")) {
            FanXPlusException.cast("课程已提交审核请等待审核");
        }
        //课程的图片，计划信息没有填写也不许提交
        String pic = courseBaseInfo.getPic();
        if (StringUtils.isEmpty(pic)) {
            FanXPlusException.cast("请上传课程图片");
        }
        //查询课程信息
        List<TeachplanDto> teachplanTree = teachplanService.findTeachplanTree(courseId);
        if (teachplanTree == null || teachplanTree.size() == 0) {
            FanXPlusException.cast("请填写课程计划");
        }
        //todo:本机构只能提交本机构的视频
        //本机构只允许提交本机构的课程
        CoursePublishPre coursePublishPre2 = coursePublishPreMapper.selectById(courseId);
        if(!coursePublishPre2.getCompanyId().equals(companyId)){
            FanXPlusException.cast("不允许提交其它机构的课程。");
        }
        //查询到课程基本信息，营销信息，计划等信息插入到课程预发布表
        CoursePublishPre coursePublishPre = new CoursePublishPre();
        BeanUtils.copyProperties(courseBaseInfo, coursePublishPre);
        //营销信息
        CourseMarket courseMarket = courseMarketMapper.selectById(courseId);
        //转Json
        String teachplanTreeJson = JSON.toJSONString(teachplanTree);
        String courseMarketJson = JSON.toJSONString(courseMarket);
        coursePublishPre.setTeachplan(teachplanTreeJson);
        coursePublishPre.setMarket(courseMarketJson);
        //状态设置为已提交
        coursePublishPre.setStatus("202003");
        //提交时间
        coursePublishPre.setCreateDate(LocalDateTime.now());
        //查询预发布表，如果有记录则更新，没有则插入
        CoursePublishPre coursePublishPre1 = coursePublishPreMapper.selectById(courseId);
        if (coursePublishPre1 == null) {
            //插入
            coursePublishPreMapper.insert(coursePublishPre);
        } else {
            //更新
            coursePublishPreMapper.updateById(coursePublishPre);
        }
        //更新课程基本信息表的审核状态为已提交
        CourseBase courseBase = courseBaseMapper.selectById(courseId);
        courseBase.setAuditStatus("202003");
        courseBaseMapper.updateById(courseBase);
    }

    @Override
    public void publish(Long companyId, Long courseId) {

        //查询预发布表
        CoursePublishPre coursePublishPre = coursePublishPreMapper.selectById(courseId);
        if (coursePublishPre==null){
            FanXPlusException.cast("课程没有审核记录,无法发布");
        }
        //课程如果没有审核通过不允许发布
        if (!coursePublishPre.getStatus().equals("202004")){
            FanXPlusException.cast("课程未通过审核不允许发布");
        }
        //向课程发布表写入数据
        CoursePublish coursePublish = new CoursePublish();
        BeanUtils.copyProperties(coursePublishPre,coursePublish);
        //先查询课程发布，如果有则更新，没有就插入
        CoursePublish coursePublish1 = coursePublishMapper.selectById(courseId);
        if (coursePublish1==null) {
            coursePublishMapper.insert(coursePublish);
        }else {
            coursePublishMapper.updateById(coursePublish);
        }
        //向消息写入数据
        //todo:
        saveCoursePublishMessage(courseId);
        //将预发布表数据删除
        coursePublishPreMapper.deleteById(courseId);
    }

    @Override
    public File generateCourseHtml(Long courseId){
        Configuration configuration = new Configuration(Configuration.getVersion());

        File htmlFile = null;
        try {
            //加载模板
            //选指定模板路径,classpath下templates下
            //得到classpath路径
//            String classpath = this.getClass().getResource("/").getPath();
//            configuration.setDirectoryForTemplateLoading(new File(classpath + "/templates/"));
            //更改为如下方式
            configuration.setTemplateLoader(new ClassTemplateLoader(this.getClass().getClassLoader(),"/templates"));

            //设置字符编码
            configuration.setDefaultEncoding("utf-8");

            //指定模板文件名称
            Template template = configuration.getTemplate("course_template.ftl");

            //准备数据
            CoursePreviewDto coursePreviewInfo = this.getCoursePreviewInfo(courseId);

            Map<String, Object> map = new HashMap<>();
            map.put("model", coursePreviewInfo);

            //静态化
            //参数1：模板，参数2：数据模型
            String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
//            System.out.println(content);
            //将静态化内容输出到文件中
            InputStream inputStream = IOUtils.toInputStream(content);
            //创建静态化文件
            htmlFile = File.createTempFile("coursepublish",".html");
            log.debug("课程静态化，生成静态文件:{}",htmlFile.getAbsolutePath());
            //输出流
            FileOutputStream outputStream = new FileOutputStream(htmlFile);
            IOUtils.copy(inputStream, outputStream);
        }catch (Exception e){
            log.error("页面静态化出现问题，课程id:{}",courseId,e);
            e.printStackTrace();
        }
        return htmlFile;
    }

    @Override
    public void uploadCourseHtml(Long courseId, File file) {
        try {
            //将file转成MultipartFile
            MultipartFile multipartFile = MultipartSupportConfig.getMultipartFile(file);
            String upload = mediaServiceClient.upload(multipartFile, "course/" + courseId + ".png");
            if(upload==null){
                log.debug("远程调用走降级逻辑得到上传的结果为null，课程id:{}",courseId);
                FanXPlusException.cast("上传静态文件过程中出现异常");
            }
        }catch (Exception e){
            e.printStackTrace();
            FanXPlusException.cast("上传静态文件过程中出现异常");
        }
    }

    /**
     * @description 保存消息表记录
     * @param courseId  课程id
     * @return void
     * @author Mr.M
     * @date 2022/9/20 16:32
     */
    private void saveCoursePublishMessage(Long courseId){
        MqMessage mqMessage = mqMessageService.addMessage("course_publish", String.valueOf(courseId), null, null);
        if(mqMessage==null){
            FanXPlusException.cast(CommonError.UNKOWN_ERROR);
        }
    }

    /**
     * 根据课程id 查询课程发布信息
     * @param courseId 课程id
     * @return 发布信息
     */
    public CoursePublish getCoursePublish(Long courseId){
        CoursePublish coursePublish = coursePublishMapper.selectById(courseId);
        return coursePublish ;
    }

    @Override
    public CoursePublish getCoursePublishCache(Long courseId) {
        //布隆过滤器
        //查询redis缓存
        Object jsonObj = redisTemplate.opsForValue().get("course:" + courseId);
        if (jsonObj != null){
            //如果缓存有直接返回数据
            String jsonString = jsonObj.toString();
            if ("null".equals(jsonString)){
                return null;
            }
            return JSON.parseObject(jsonString,CoursePublish.class);
        }else {
            //从数据库查询
            CoursePublish coursePublish = getCoursePublish(courseId);
           // if (coursePublish !=null) {
                //查询完成存入redis
                redisTemplate.opsForValue().set("course:" + courseId, JSON.toJSONString(coursePublish),30, TimeUnit.SECONDS);
           // }
            return coursePublish;
        }


    }
}
